home *** CD-ROM | disk | FTP | other *** search
/ Clickx 47 / Clickx 47.iso / assets / software / Miro_Installer.exe / xulrunner / python / guide.py < prev    next >
Encoding:
Python Source  |  2008-01-10  |  8.4 KB  |  259 lines

  1. # Miro - an RSS based video player application
  2. # Copyright (C) 2005-2007 Participatory Culture Foundation
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  17.  
  18. import resources
  19. from database import DDBObject
  20. from template import fillStaticTemplate
  21. from httpclient import grabURL
  22. from urlparse import urlparse, urljoin
  23. from xhtmltools import urlencode
  24. from copy import copy
  25. from util import returnsUnicode, unicodify, checkU
  26. import re
  27. import app
  28. import config
  29. import indexes
  30. import menu
  31. import prefs
  32. import threading
  33. import urllib
  34. import eventloop
  35. import views
  36. import logging
  37. import httpclient
  38. from gtcache import gettext as _
  39. from HTMLParser import HTMLParser,HTMLParseError
  40. import iconcache
  41.  
  42. HTMLPattern = re.compile("^.*(<head.*?>.*</body\s*>)", re.S)
  43.  
  44. def isPartOfGuide(url, guideURL, allowedURLs = None):
  45.     """Return if url is part of a channel guide where guideURL is the base URL
  46.     for that guide.
  47.     """
  48.     if guideURL == "*":
  49.         return True
  50.     elif guideURL.startswith('file://'):
  51.         return False
  52.     elif allowedURLs is None:
  53.         guideHost = urlparse(guideURL)[1]
  54.         urlHost = urlparse(url)[1]
  55.         return urlHost.endswith(guideHost)
  56.     else:
  57.         if isPartOfGuide(url, guideURL):
  58.             return True
  59.         for altURL in allowedURLs:
  60.             if isPartOfGuide(url, altURL):
  61.                 return True
  62.         return False
  63. class ChannelGuide(DDBObject):
  64.     ICON_CACHE_SIZES = [
  65. #        (20, 20),
  66.     ]
  67.     def __init__(self, url, allowedURLs = None):
  68.         checkU(url)
  69.         if allowedURLs is None:
  70.             self.allowedURLs = []
  71.         else:
  72.             self.allowedURLs = allowedURLs
  73.         self.url = url
  74.         self.updated_url = url
  75.         self.title = None
  76.         self.lastVisitedURL = None
  77.         self.iconCache = iconcache.IconCache(self, is_vital = True)
  78.         self.favicon = None
  79.         self.firstTime = True
  80.         if url:
  81.             self.historyLocation = 0
  82.             self.history = [self.url]
  83.         else:
  84.             self.historyLocation = None
  85.             self.history = []
  86.  
  87.         DDBObject.__init__(self)
  88.         self.downloadGuide()
  89.  
  90.     def onRestore(self):
  91.         self.lastVisitedURL = None
  92.         self.historyLocation = None
  93.         self.history = []
  94.         if (self.iconCache == None):
  95.             self.iconCache = iconcache.IconCache (self, is_vital = True)
  96.         else:
  97.             self.iconCache.dbItem = self
  98.             self.iconCache.requestUpdate(True)
  99.         if self.getDefault():
  100.             self.allowedURLs = config.get(prefs.CHANNEL_GUIDE_ALLOWED_URLS).split()
  101.             self.allowedURLs.append(config.get(prefs.CHANNEL_GUIDE_FIRST_TIME_URL))
  102.         else:
  103.             self.allowedURLs = []
  104.         self.downloadGuide()
  105.  
  106.  
  107.     def __str__(self):
  108.         return "Miro Guide <%s>" % (self.url,)
  109.  
  110.     def makeContextMenu(self, templateName, view):
  111.         menuItems = [
  112.             (lambda: app.delegate.copyTextToClipboard(self.getURL()),
  113.                 _('Copy URL to clipboard')),
  114.         ]
  115.         if not self.getDefault():
  116.             i = (lambda: app.controller.removeGuide(self), _('Remove'))
  117.             menuItems.append(i)
  118.         return menu.makeMenu(menuItems)
  119.  
  120.     def remove(self):
  121.         if self.iconCache is not None:
  122.             self.iconCache.remove()
  123.             self.iconCache = None
  124.         DDBObject.remove(self)
  125.  
  126.     def isPartOfGuide(self, url):
  127.         return isPartOfGuide(url, self.getURL(), self.allowedURLs)
  128.  
  129.     def getURL(self):
  130.         return self.url
  131.  
  132.     def getFirstURL(self):
  133.         if self.getDefault():
  134.             return config.get(prefs.CHANNEL_GUIDE_FIRST_TIME_URL)
  135.         else:
  136.             return self.url
  137.  
  138.     def getLastVisitedURL(self):
  139.         if self.lastVisitedURL is not None:
  140.             logging.info("First URL is %s"%self.lastVisitedURL)
  141.             return self.lastVisitedURL
  142.         else:
  143.             if self.firstTime:
  144.                 self.firstTime = False
  145.                 logging.info("First URL is %s"%self.getFirstURL())
  146.                 return self.getFirstURL()
  147.             else:
  148.                 logging.info("First URL is %s"%self.getURL())
  149.                 return self.getURL()
  150.  
  151.     def getDefault(self):
  152.         return self.url == config.get(prefs.CHANNEL_GUIDE_URL)
  153.  
  154.     # For the tabs
  155.     @returnsUnicode
  156.     def getTitle(self):
  157.         if self.title:
  158.             return self.title
  159.         else:
  160.             return self.getURL()
  161.  
  162.     def guideDownloaded(self, info):
  163.         self.updated_url = unicode(info["updated-url"])
  164.         try:
  165.             parser = GuideHTMLParser(self.updated_url)
  166.             parser.feed(info["body"])
  167.             parser.close()
  168.         except:
  169.             pass
  170.         else:
  171.             self.title = unicode(parser.title)
  172.             self.favicon = unicode(parser.favicon)
  173.             self.extendHistory(self.updated_url)
  174.             self.iconCache.requestUpdate()
  175.             self.signalChange()
  176.  
  177.     def guideError (self, error):
  178.         pass
  179.  
  180.     def downloadGuide(self):
  181.         httpclient.grabURL(self.getURL(), self.guideDownloaded, self.guideError)
  182.  
  183.     @returnsUnicode
  184.     def getIconURL(self):
  185.         if self.iconCache.isValid():
  186.             path = self.iconCache.getResizedFilename(20, 20)
  187.             return resources.absoluteUrl(path)
  188.         else:
  189.             return resources.url("images/channelguide-icon-tablist.png")
  190.  
  191.     def getThumbnailURL(self):
  192.         if self.favicon:
  193.             return self.favicon
  194.         else:
  195.             if self.updated_url:
  196.                 parsed = urlparse(self.updated_url)
  197.             else:
  198.                 parsed = urlparse(self.getURL())
  199.             return parsed[0] + u"://" + parsed[1] + u"/favicon.ico"
  200.  
  201.     def extendHistory(self, url):
  202.         if self.historyLocation is None:
  203.             self.historyLocation = 0
  204.             self.history = [url]
  205.         else:
  206.             if self.history[self.historyLocation] == url: # moved backwards
  207.                 return
  208.             if self.historyLocation != len(self.history) - 1:
  209.                 self.history = self.history[:self.historyLocation+1]
  210.             self.history.append(url)
  211.             self.historyLocation += 1
  212.  
  213.  
  214.     def getHistoryURL(self, direction):
  215.         if direction is not None:
  216.             location = self.historyLocation + direction
  217.             if location < 0:
  218.                 return
  219.             elif location >= len(self.history):
  220.                 return
  221.         else:
  222.             location = 0 # go home
  223.         self.historyLocation = location
  224.         return self.history[self.historyLocation]
  225.  
  226. # Grabs the feed link from the given webpage
  227. class GuideHTMLParser(HTMLParser):
  228.     def __init__(self, url):
  229.         self.title = None
  230.         self.in_title = False
  231.         self.baseurl = url
  232.         self.favicon = None
  233.         HTMLParser.__init__(self)
  234.  
  235.     def handle_starttag(self, tag, attrs):
  236.         attrdict = {}
  237.         for (key, value) in attrs:
  238.             attrdict[key] = value
  239.         if tag == 'title' and self.title == None:
  240.             self.in_title = True
  241.             self.title = u""
  242.         if (tag == 'link' and attrdict.has_key('rel') and
  243.             attrdict.has_key('type') and attrdict.has_key('href') and
  244.             'icon' in attrdict['rel'].split(' ') and
  245.             attrdict['type'].startswith("image/")):
  246.  
  247.             self.favicon = urljoin(self.baseurl,attrdict['href']).decode('ascii', 'ignore')
  248.  
  249.     def handle_data(self, data):
  250.         if self.in_title:
  251.             self.title += data
  252.  
  253.     def handle_endtag(self, tag):
  254.         if tag == 'title' and self.in_title:
  255.             self.in_title = False
  256.  
  257. def getGuideByURL(url):
  258.     return views.guides.getItemWithIndex(indexes.guidesByURL, url)
  259.